package cn.coders.haoniu.caipiao.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.Entity;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import cn.coders.haoniu.caipiao.dao.BaseDao;


/**
 * Dao实现类 - Dao实现类基类
 */

public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {
    private Class<T> entityClass;
    @Autowired
    protected SessionFactory sessionFactory;


    @SuppressWarnings({ "unchecked", "rawtypes" })
    public BaseDaoImpl() {
        this.entityClass = null;
        Class c = getClass();
        Type type = c.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
    }


    @Resource
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }


    protected Session getSession() {
        Session session = null;
        try {
            session = sessionFactory.getCurrentSession();
        }
        catch (HibernateException e) {
            e.printStackTrace();
        }
        return session;
    }


    @SuppressWarnings("unchecked")
    public T get(PK id) {
        Session session = getSession();
        T t = (T) session.get(entityClass, id);
        return t;
    }


    @SuppressWarnings("unchecked")
    public T load(PK id) {
        Session session = getSession();
        T t = (T) session.load(entityClass, id);
        return t;
    }


    /**
     * 根据hql语句获取集合
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<T> getList(String hql) {
        Session session = getSession();
        Query q = session.createQuery(hql);
        return q.list();
    }


    @SuppressWarnings("unchecked")
    public List<T> get(PK[] ids) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where model.id in(:ids)";
        Query q = session.createQuery(hql).setParameterList("ids", ids);
        List<T> list = q.list();
        return list;
    }


    /**
     * 根据HQL语句查询数据
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<T> executeQuery(String hql) {
        Session session = getSession();
        Query q = session.createQuery(hql);
        List<T> list = q.list();
        return list;
    }


    @SuppressWarnings("unchecked")
    public T get(String propertyName, Object value) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
        List<T> t = session.createQuery(hql).setParameter(0, value).list();
        if (t.size() > 0) {
            return t.get(0);
        }
        return null;
    }


    @SuppressWarnings("unchecked")
    public T get(Map<String, Object> propertyMap) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where ";
        Iterator<String> keyIterator = propertyMap.keySet().iterator();
        List<String> keyArr = new ArrayList<String>(propertyMap.size());
        String key = keyIterator.next();
        keyArr.add(key);
        hql += "model." + key + " = ?";
        while (keyIterator.hasNext()) {
            key = keyIterator.next();
            keyArr.add(key);
            hql += " and model." + key + " = ?";
        }
        Query q = session.createQuery(hql);
        for (int i = 0; i < keyArr.size(); i++) {
            q.setParameter(i, propertyMap.get(keyArr.get(i)));
        }
        T t = (T) q.uniqueResult();
        return t;
    }


    @SuppressWarnings("unchecked")
    public List<T> getList(String propertyName, Object value) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
        Query q = session.createQuery(hql).setParameter(0, value);
        List<T> list = q.list();
        return list;
    }


    /**
     * 根据条件查询。条件为propertyName!=value
     * **/
    @SuppressWarnings("unchecked")
    public List<T> getNoList(String propertyName, Object value) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " != ?";
        Query q = session.createQuery(hql).setParameter(0, value);
        List<T> list = q.list();
        return list;
    }


    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        Session session = getSession();
        String hql = "from " + entityClass.getName();
        List<T> list = null;
        try {
            list = session.createQuery(hql).list();
        }
        catch (HibernateException e) {
            e.printStackTrace();
        }
        return list;
    }


    @SuppressWarnings("unchecked")
    public List<T> getAll(String hql) {
        Session session = getSession();
        List<T> list = null;
        try {
            list = session.createQuery(hql).list();
        }
        catch (HibernateException e) {
            e.printStackTrace();
        }
        return list;
    }


    public Long getTotalCount() {
        Session session = getSession();
        String hql = "select count(*) from " + entityClass.getName();
        Long total = (Long) session.createQuery(hql).uniqueResult();
        return total;
    }


    public Long getTotalCountGroupByProerty(String groupByName) {
        Session session = getSession();
        String hql = "select count(*) from " + entityClass.getName() + " group by ?";
        Long total = (Long) session.createQuery(hql).setParameter(0, groupByName).uniqueResult();
        return total;
    }


    public Long getTotalCount(String propertyName, Object value) {
        Session session = getSession();
        String hql =
                "select count(*) from " + entityClass.getName() + " as model where model." + propertyName
                        + " = ?";
        Long total = (Long) session.createQuery(hql).setParameter(0, value).uniqueResult();
        return total;
    }


    public Double getSumTotal(String propertySum) {
        Session session = getSession();
        String hql = "select sum(" + propertySum + ") from " + entityClass.getName();
        Double total = (Double) session.createQuery(hql).uniqueResult();
        return total;
    }


    public Double getSumTotal(String propertySum, String propertyName, Object value) {
        Session session = getSession();
        String hql =
                "select sum(" + propertySum + ") from " + entityClass.getName() + " as model where model."
                        + propertyName + " = ?";
        Double total = (Double) session.createQuery(hql).setParameter(0, value).uniqueResult();
        return total;
    }


    public boolean isUnique(String propertyName, Object oldValue, Object newValue) {
        if (newValue == oldValue || newValue.equals(oldValue)) {
            return true;
        }
        if (newValue instanceof String) {
            if (oldValue != null && StringUtils.equalsIgnoreCase((String) oldValue, (String) newValue)) {
                return true;
            }
        }
        T object = get(propertyName, newValue);
        return (object == null);
    }


    public boolean isExist(String propertyName, Object value) {
        T object = get(propertyName, value);
        return (object != null);
    }


    @SuppressWarnings("unchecked")
    public PK save(T entity) {
        return (PK) getSession().save(entity);
    }


    public void update(T entity) {
        Session session = getSession();
        // Transaction tran=session.beginTransaction();
        // tran.begin();
        session.update(entity);
        // tran.commit();

    }


    public void merge(T entity) {
        // TODO Auto-generated method stub
        getSession().merge(entity);
    }


    public void delete(T entity) {
        getSession().delete(entity);
    }


    public void delete(PK id) {
        T entity = load(id);
        getSession().delete(entity);
    }


    public void delete(PK[] ids) {
        for (PK id : ids) {
            T entity = load(id);
            getSession().delete(entity);
        }
    }


    public void flush() {
        getSession().flush();
    }


    public void clear() {
        getSession().clear();
    }


    public void evict(Object object) {
        getSession().evict(object);
    }


    public Long getTotalCount(String propertyName, Object value, String whereName, Object whereObject) {
        Session session = getSession();
        String hql =
                "select count(*) from " + entityClass.getName() + " as model where model." + propertyName
                        + " = ? and model." + whereName + " = ?";
        Long total =
                (Long) session.createQuery(hql).setParameter(0, value).setParameter(1, whereObject)
                    .uniqueResult();
        return total;
    }


    public List<T> getList(Map<String, Object> propertyMap) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where ";
        Iterator<String> keyIterator = propertyMap.keySet().iterator();
        List<String> keyArr = new ArrayList<String>(propertyMap.size());
        String key = keyIterator.next();
        keyArr.add(key);
        hql += "model." + key + " = ?";
        while (keyIterator.hasNext()) {
            key = keyIterator.next();
            keyArr.add(key);
            hql += " and model." + key + " = ?";
        }
        Query q = session.createQuery(hql);
        for (int i = 0; i < keyArr.size(); i++) {
            q.setParameter(i, propertyMap.get(keyArr.get(i)));
        }
        @SuppressWarnings("unchecked")
        List<T> list = q.list();
        return list;
    }


    public List<T> getNoList(Map<String, Object> propertyMap) {
        Session session = getSession();
        String hql = "from " + entityClass.getName() + " as model where ";
        Iterator<String> keyIterator = propertyMap.keySet().iterator();
        List<String> keyArr = new ArrayList<String>(propertyMap.size());
        String key = keyIterator.next();
        keyArr.add(key);
        hql += "model." + key + " != ?";
        while (keyIterator.hasNext()) {
            key = keyIterator.next();
            keyArr.add(key);
            hql += " and model." + key + " != ?";
        }
        Query q = session.createQuery(hql);
        for (int i = 0; i < keyArr.size(); i++) {
            q.setParameter(i, propertyMap.get(keyArr.get(i)));
        }
        @SuppressWarnings("unchecked")
        List<T> list = q.list();
        return list;
    }


    @SuppressWarnings("unchecked")
    public T like(String propertyName, Object value) {
        Session session = getSession();
        String hql =
                "from " + entityClass.getName() + " as model where model." + propertyName + " like '%"
                        + value.toString() + "%'";
        T t = (T) session.createQuery(hql).uniqueResult();
        return t;
    }


    public <T> Criteria createCriteria(Class<T> entityClass) {
        Criteria criteria = getSession().createCriteria(entityClass);
        return criteria;
    }


    /**
     * @param <T>
     * @param entityClass
     * @return 通过字节码得到实体名；
     */
    protected <T> String getEntityName(Class<T> entityClass) {
        String queryName = null;
        Entity entity = entityClass.getAnnotation(Entity.class);
        if (entityClass != null) {
            queryName = entityClass.getName();
        }
        return queryName;
    }


    public int countRecord(String hql) {
        int l = Integer.parseInt(executeQuery(hql).get(0).toString());
        return l;
    }


    /**
     * 加入条件的获取数据
     * 
     * @param object
     * @param whereStr
     * @param orderbyStr
     * @param groupByStr
     * @return
     */
    public List find(Class object, String filedName, String whereStr, String orderbyStr, String groupByStr) {
        StringBuffer jpql = new StringBuffer();
        // jpql.append("from " + getEntityName(object) + " a ");

        if (StringUtils.isNotBlank(filedName) && filedName == "*") {
            jpql.append("select a from " + getEntityName(object) + " a ");
        }
        else if (StringUtils.isNotBlank(filedName) && filedName != "*") {
            jpql.append("select a." + filedName + " from " + getEntityName(object) + " a ");
        }

        if (StringUtils.isNotBlank(whereStr)) {
            jpql.append("where  a." + whereStr);
        }

        if (StringUtils.isNotBlank(orderbyStr)) {
            jpql.append(" order by   a." + orderbyStr);
        }

        if (StringUtils.isNotBlank(groupByStr)) {
            jpql.append(" group by   a." + groupByStr);
        }
        return executeQuery(jpql.toString());
    }


    public Long getTotalCount(Map<String, Object> propertyMap) {
        Session session = getSession();
        String hql = "select count(1) from " + entityClass.getName() + " as model where ";
        Iterator<String> keyIterator = propertyMap.keySet().iterator();
        List<String> keyArr = new ArrayList<String>(propertyMap.size());
        String key = keyIterator.next();
        keyArr.add(key);
        hql += "model." + key + " = ?";
        while (keyIterator.hasNext()) {
            key = keyIterator.next();
            keyArr.add(key);
            hql += " and model." + key + " = ?";
        }
        Long total = (Long) session.createQuery(hql).uniqueResult();
        return total;
    }


    public List findBySql(String sql) {
        // TODO Auto-generated method stub
        Session session = getSession();
        String sqlString = sql;
        List list = null;
        try {
            Query query = session.createSQLQuery(sqlString);
            list = query.list();
        }
        catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {

        }
        return list;

    }


    public int findTotalSQL(String hql) {
        int numb = 0;
        Session session = this.getSession();
        List li = session.createSQLQuery(hql).list();

        BigInteger obj = (BigInteger) li.get(0);
        // releaseSession(session);
        if (obj != null && !obj.equals("") && !obj.equals("null")) {
            numb = obj.intValue();
        }
        return numb;
    }


    @Override
    public List<T> find(String query, Object[] params, int begin, int max) {
        // TODO Auto-generated method stub
        return null;
    }

}